home *** CD-ROM | disk | FTP | other *** search
/ PC Media 7 / PC MEDIA CD07.iso / share / prog / cm / cmbtree.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-06  |  19.6 KB  |  669 lines

  1. // CmBTree.cpp
  2. // -----------------------------------------------------------------
  3. // Compendium - C++ Container Class Library
  4. // Copyright (C) 1992-1994, Glenn M. Poorman, All rights reserved
  5. // -----------------------------------------------------------------
  6. // Balanced tree implementation.
  7. // -----------------------------------------------------------------
  8.  
  9. #include <cm/include/cmbtree.h>
  10.  
  11.  
  12. // "CmBTree" is the default tree constructor.
  13. // (BTree order can not be less than 3).
  14. //
  15. CmBTree::CmBTree(unsigned ordr)
  16. {
  17.   _order = (ordr >= 3) ? ordr : 3;
  18.   _root  = NULL;
  19. }
  20.  
  21.  
  22. // "CmBTree" is the tree copy constructor.
  23. //
  24. CmBTree::CmBTree(const CmBTree& T)
  25. {
  26.   _order = T._order;
  27.   _root  = NULL;
  28.   copy(T);
  29. }
  30.  
  31.  
  32. // "~CmBTree" is the tree destructor.
  33. //
  34. CmBTree::~CmBTree()
  35. {
  36.   removeAll();
  37. }
  38.  
  39.  
  40. // "=" assignment operator copies the specified tree into this tree.
  41. //
  42. CmBTree& CmBTree::operator=(const CmBTree& T)
  43. {
  44.   if (&T != this)
  45.   {
  46.     removeAll();
  47.     _order = T._order;
  48.     copy(T);
  49.   }
  50.   return *this;
  51. }
  52.  
  53.  
  54. // "height" returns the current tree height.
  55. //
  56. unsigned CmBTree::height() const
  57. {
  58.   CmBTreeNode *rover = _root;
  59.   unsigned     ht    = 0;
  60.   while (rover)
  61.   {
  62.     ht++;
  63.     rover = rover->_children[0];
  64.   }
  65.   return ht;
  66. }
  67.  
  68.  
  69. // "add" adds a new object to the tree.
  70. //
  71. Bool CmBTree::add(CmObject* pObj)
  72. {
  73.   CmObject    *data  = pObj;                // Initialize data object.
  74.   CmBTreeNode *child = NULL;                // Initialize child.
  75.   CmBTreeNode *rover = nodeSearch(pObj);    // Find node to insert into.
  76.   Bool         done  = FALSE;               // Loop flag.
  77.  
  78.   while (rover && !done)                    // Loop.
  79.   {
  80.     int idx = rover->shouldGo(data);        // Get position for new object.
  81.     rover->addAt(idx, data, child, 1);      // Add new data and child to node.
  82.     if (rover->_total <= _order-1)          // Data fits so exit.
  83.       done = TRUE;
  84.     else
  85.     {
  86.       data = rover->_data[(rover->_total) / 2];     // Data doesn't fit.
  87.       CmBTreeNode *newRight = rover->split(_order); // Split the node.
  88.       if (!newRight) return FALSE;                  // Split unsuccessful.
  89.       child = newRight;                             // Set new child to right.
  90.       rover = rover->_parent;                       // Move to parent.
  91.     }
  92.   }
  93.  
  94.   if (!done)                                    // Not done, create a
  95.   {                                             // new root.
  96.     CmBTreeNode *newRoot  = new CmBTreeNode(NULL, _order);
  97.     newRoot->_children[0] = _root;              // Old root is child of new.
  98.     newRoot->_children[1] = child;              // Stray child is also child.
  99.     newRoot->_data    [0] = data;               // Data is lone root object.
  100.     newRoot->_total       = 1;                  // New root contains 1.
  101.  
  102.     if (_root)                                  // Set parentage of children
  103.     {                                           // if not first time in.
  104.       child->_parent = newRoot;
  105.      _root->_parent  = newRoot;
  106.     }
  107.     _root = newRoot;                            // New root is now root.
  108.   }
  109.   _size++;                                      // Bump size and split.
  110.   return TRUE;
  111. }
  112.  
  113.  
  114. // "remove" removes the first occurrence of an object that isEqual
  115. // to the specified object from the tree.
  116. //
  117. Bool CmBTree::remove(CmObject* pObj)
  118. {
  119.   CmBTreeNode *node = lookupNode(pObj);         // Find node where object is.
  120.   if (!node) return FALSE;                      // No object, exit.
  121.  
  122.   int idx = node->index(pObj);                  // Get index of object in node.
  123.   if (idx == -1) return FALSE;                  // No object, exit.
  124.   if (ownsObjects()) delete node->_data[idx];   // Delete object if owned.
  125.   _size--;                                      // Decrement size.
  126.  
  127.   if (node->_children[0])                       // If node is not leaf, swap
  128.   {                                             // object with object at left
  129.     CmBTreeNode *rover = node->_children[idx+1];  // most side of right branch.
  130.     while (rover->_children[0]) rover = rover->_children[0];
  131.     node->_data[idx] = rover->_data[0];
  132.     node = rover;
  133.     idx  = 0;
  134.   }
  135.  
  136.   node->removeAt(idx);                         // Remove object from node.
  137.   unsigned minkeys = minKeys(_order);          // Save min allowable keys.
  138.  
  139.   while (node != _root && node->_total < minkeys)  // Start looping if number
  140.   {                                                // of keys fell below min.
  141.     int nodeIdx = node->_parent->index(node);  // Save index of node in parent.
  142.     if (nodeIdx == -1) return FALSE;
  143.  
  144.     if (node->_parent->_children[nodeIdx+1])   // If node has a right sibling,
  145.     {
  146.       CmBTreeNode *sib = node->_parent->_children[nodeIdx+1];
  147.       CmBTreeNode *par = node->_parent;
  148.  
  149.       // If the right sibling has keys to spare, move the left most key in
  150.       // the right sibling up to the parent.  Take the parent key parenting
  151.       // this node and move that key into this node.  Exit.
  152.       if (sib->_total > minkeys)
  153.       {
  154.         node->addAt(node->_total, par->_data[nodeIdx], sib->_children[0], 1);
  155.         if (sib->_children[0]) sib->_children[0]->_parent = node;
  156.         par->_data[nodeIdx] = sib->_data[0];
  157.         sib->removeAt(0);
  158.         return TRUE;
  159.       }
  160.  
  161.       // The right sibling has no keys to spare, so we need to combine the
  162.       // remaining keys in this node with the parent key parenting this node
  163.       // and the keys of the right sibling to form one node.
  164.       node->addAt(node->_total, par->_data[nodeIdx], sib->_children[0], 1);
  165.       for (int ii = 0; ii < sib->_total; ii++)
  166.       {
  167.         node->addAt(node->_total, sib->_data[ii], sib->_children[ii+1], 1);
  168.         if (sib->_children[ii+1]) sib->_children[ii+1]->_parent = node;
  169.       }
  170.       delete sib;
  171.       par->removeAt(nodeIdx);
  172.       node = par;
  173.     }
  174.  
  175.     else if (node->_parent->_children[nodeIdx-1]) // If node has left sibling,
  176.     {
  177.       CmBTreeNode *sib = node->_parent->_children[nodeIdx-1];
  178.       CmBTreeNode *par = node->_parent;
  179.  
  180.       // If the left sibling has keys to spare, move the right most key in
  181.       // the left sibling up to the parent.  Take the parent key parenting
  182.       // the left sibling and move that key into this node.  Exit.
  183.       if (sib->_total > minkeys)
  184.       {
  185.         node->addAt(0, par->_data[nodeIdx-1], sib->_children[sib->_total], 0);
  186.         if (sib->_children[sib->_total])
  187.           sib->_children[sib->_total]->_parent = node;
  188.         par->_data[nodeIdx-1] = sib->_data[sib->_total-1];
  189.         sib->removeAt(sib->_total-1);
  190.         return TRUE;
  191.       }
  192.  
  193.       // The left sibling has no keys to spare, so we need to combine the
  194.       // keys in the left sibling with the parent key parenting the left
  195.       // sibling and the keys of this node to form one node.
  196.       sib->addAt(sib->_total, par->_data[nodeIdx-1], node->_children[0], 1);
  197.       for (int ii = 0; ii < node->_total; ii++)
  198.       {
  199.         sib->addAt(sib->_total, node->_data[ii], node->_children[ii+1], 1);
  200.         if (node->_children[ii+1]) node->_children[ii+1]->_parent = sib;
  201.       }
  202.       delete node;
  203.       par->removeAt(nodeIdx-1);
  204.       node = par;
  205.     }
  206.   }
  207.  
  208.   if (node->_total == 0)                // If only the root node is left,
  209.   {                                     // and it has no keys, then delete
  210.     CmBTreeNode *temp = _root;          // delete the root node and make
  211.     _root = _root->_children[0];        // it's left most child the new
  212.     delete temp;                        // root node.
  213.   }
  214.   if (_root && _root->_parent) _root->_parent = NULL;
  215.   return TRUE;
  216. }
  217.  
  218.  
  219. // "lookup" returns the first occurrence of an object which isEqual
  220. // to the specified object.
  221. //
  222. CmObject* CmBTree::lookup(CmObject* pObj) const
  223. {
  224.   if (!pObj || !_root) return NULL;
  225.  
  226.   CmBTreeNode *node = lookupNode(pObj);    // Find node where object is.
  227.   if (!node) return NULL;
  228.  
  229.   int idx = node->index(pObj);
  230.   return (idx == -1) ? NULL : node->_data[idx];
  231. }
  232.  
  233.  
  234. // "contains" checks to see if an object that isEqual to the specified
  235. // object exists in the tree.
  236. //
  237. Bool CmBTree::contains(CmObject* pObj) const
  238. {
  239.   if (!pObj || !_root) return NULL;
  240.  
  241.   CmBTreeNode *node = lookupNode(pObj);    // Find node where object is.
  242.   if (!node) return FALSE;
  243.  
  244.   int idx = node->index(pObj);
  245.   return (idx != -1) ? TRUE : FALSE;
  246. }
  247.  
  248.  
  249. // "occurrences" returns the number of objects in the tree
  250. // isEqual to the specified object.
  251. //
  252. unsigned CmBTree::occurrences(CmObject* pObj) const
  253. {
  254.   unsigned        occur    = 0;
  255.   CmBTreeIterator iterator(*this);
  256.   while (!iterator.done())
  257.   {
  258.     CmObject *temp = iterator.next();
  259.     if (pObj->compare(temp) == 0) occur++;
  260.   }
  261.   return occur;
  262. }
  263.  
  264.  
  265. // "removeAll" removes all objects from the tree.
  266. //
  267. void CmBTree::removeAll()
  268. {
  269.   removeNodes(_root, ownsObjects());
  270.   _root = NULL;
  271.   _size = 0;
  272. }
  273.  
  274.  
  275. // "newIterator" creates and returns a new tree iterator.
  276. //
  277. CmIterator* CmBTree::newIterator() const
  278. {
  279.   return new CmBTreeIterator(*this);
  280. }
  281.  
  282.  
  283. // "nodeSearch" searches for and returns a pointer to the node
  284. // where the specified object is to be inserted.
  285. //
  286. CmBTreeNode* CmBTree::nodeSearch(CmObject* pObj) const
  287. {
  288.   CmBTreeNode *rover = _root;
  289.   CmBTreeNode *found = NULL;
  290.  
  291.   while (rover && !found)
  292.   {
  293.     int idx = rover->shouldGo(pObj);
  294.     if (rover->_children[idx]) rover = rover->_children[idx];
  295.     else                       found = rover;
  296.   }
  297.   return found;
  298. }
  299.  
  300.  
  301. // "lookupNode" returns a pointer to the node where the first occurrence
  302. // of an object isEqual to the specified object was found.
  303. //
  304. CmBTreeNode* CmBTree::lookupNode(CmObject* pObj) const
  305. {
  306.   if (!pObj || !_root) return NULL;
  307.  
  308.   CmBTreeNode *rover = _root;             // Start at root node.
  309.   CmBTreeNode *ret   = NULL;
  310.   while (rover && !ret)
  311.   {
  312.     int idx = rover->index(pObj);         // Is object in node?
  313.     if (idx != -1)
  314.       ret = rover;                        // Yes.
  315.     else
  316.     {
  317.       idx   = rover->shouldGo(pObj);      // No.  Set node to point to
  318.       rover = rover->_children[idx];      // child where object would be.
  319.     }
  320.   }
  321.   return ret;
  322. }
  323.  
  324.  
  325. // "lookupAbs" returns a pointer to the node where the exact object
  326. // specified was found (addresses are compared always).
  327. //
  328. CmBTreeNode* CmBTree::lookupAbs(CmObject* pObj) const
  329. {
  330.   if (!pObj || !_root) return NULL;
  331.  
  332.   CmBTreeNode *rover = _root;             // Start at root node.
  333.   CmBTreeNode *ret   = NULL;
  334.   while (rover && !ret)
  335.   {
  336.     int idx = rover->indexAbs(pObj);      // Is object in node?
  337.     if (idx != -1)
  338.       ret = rover;                        // Yes.
  339.     else
  340.     {
  341.       idx   = rover->shouldGo(pObj);      // No.  Set node to point to
  342.       rover = rover->_children[idx];      // child where object would be.
  343.     }
  344.   }
  345.   return ret;
  346. }
  347.  
  348.  
  349. // "removeNodes" recursively calls itself to remove the nodes below
  350. // the specified node and also deletes the specified node.
  351. //
  352. void CmBTree::removeNodes(CmBTreeNode* pNode, Bool owns)
  353. {
  354.   if (pNode)
  355.   {
  356.     for (int ii = 0; ii < pNode->_total; ii++)
  357.     {
  358.       if (owns) delete pNode->_data[ii];
  359.       removeNodes(pNode->_children[ii], owns);
  360.     }
  361.     removeNodes(pNode->_children[pNode->_total], owns);
  362.     delete pNode;
  363.   }
  364. }
  365.  
  366.  
  367. // "CmBTreeNode" is the constructor for the node class.
  368. //
  369. CmBTreeNode::CmBTreeNode(CmBTreeNode* parent, unsigned order)
  370. {
  371.   _total    = 0;
  372.   _parent   = parent;
  373.   _data     = new CmObject*   [order];
  374.   _children = new CmBTreeNode*[order+1];
  375.   if (_data && _children) clear(order);
  376. }
  377.  
  378.  
  379. // "~CmBTreeNode" is the destructor for the node class.
  380. //
  381. CmBTreeNode::~CmBTreeNode()
  382. {
  383.   delete[] _data;
  384.   delete[] _children;
  385. }
  386.  
  387.  
  388. // "shouldGo" returns the index of where the specified object would
  389. // be inserted into the data list if add were called.
  390. //
  391. int CmBTreeNode::shouldGo(CmObject* pObj) const
  392. {
  393.   if (!pObj)       return -1;
  394.   if (_total == 0) return 0;
  395.  
  396.   if (pObj->compare(_data[0])        <  0) return 0;
  397.   if (pObj->compare(_data[_total-1]) >= 0) return _total;
  398.  
  399.   int idx = -1;
  400.   int ii  = _total-1;
  401.   while (ii >= 0 && idx == -1)
  402.     if (pObj->compare(_data[ii--]) >= 0) idx = ii+2;
  403.   return idx;
  404. }
  405.  
  406.  
  407. // "index" returns the index in the data list of the first occurrence
  408. // of an object isEqual to the specified object.
  409. //
  410. int CmBTreeNode::index(CmObject* pObj) const
  411. {
  412.   if (_total == 0 || !pObj) return -1;
  413.   int idx = -1;
  414.   int ii  = 0;
  415.   while (ii < _total && idx == -1)
  416.     if (pObj->compare(_data[ii++]) == 0) idx = ii-1;
  417.   return idx;
  418. }
  419.  
  420.  
  421. // "indexAbs" returns the index in the data list of the exact object
  422. // specified (addresses are compared always).
  423. //
  424. int CmBTreeNode::indexAbs(CmObject* pObj) const
  425. {
  426.   if (_total == 0 || !pObj) return -1;
  427.   int idx = -1;
  428.   int ii  = 0;
  429.   while (ii < _total && idx == -1)
  430.     if (pObj == _data[ii++]) idx = ii-1;
  431.   return idx;
  432. }
  433.  
  434.  
  435. // "index" returns the index in the child list of the specified node.
  436. //
  437. int CmBTreeNode::index(CmBTreeNode* pNode) const
  438. {
  439.   if (_total == 0 || !pNode) return -1;
  440.   int idx = -1;
  441.   int ii  = 0;
  442.   while (ii <= _total && idx == -1)
  443.     if (pNode == _children[ii++]) idx = ii-1;
  444.   return idx;
  445. }
  446.  
  447.  
  448. // "addAt" adds the specified object/child to this node's lists at the
  449. // specified index.
  450. //
  451. Bool CmBTreeNode::addAt(int idx, CmObject* pObj, CmBTreeNode* pNode, int offset)
  452. {
  453.   if (offset == 0) _children[_total+1] = _children[_total];
  454.   for (int ii = _total; ii > idx; ii--)     // Slide other stuff to make
  455.   {                                         // room.
  456.     _data    [ii       ] = _data    [ii-1];
  457.     _children[ii+offset] = _children[ii+offset-1];
  458.   }
  459.  
  460.   _data    [idx       ] = pObj;             // Insert object and child.
  461.   _children[idx+offset] = pNode;
  462.   _total++;
  463.   return TRUE;
  464. }
  465.  
  466.  
  467. // "removeAt" removes the object at the specified index in the node's
  468. // data list and removes the right child of that object.
  469. //
  470. Bool CmBTreeNode::removeAt(int idx)
  471. {
  472.   if (idx < 0 || idx >= _total) return FALSE;
  473.  
  474.   for (int ii = idx; ii < _total-1; ii++)
  475.   {
  476.     _data    [ii  ] = _data    [ii+1];
  477.     _children[ii+1] = _children[ii+2];
  478.   }
  479.   _data    [_total-1] = NULL;
  480.   _children[_total  ] = NULL;
  481.   _total--;
  482.   return TRUE;
  483. }
  484.  
  485.  
  486. // "clear" nulls out the data and child arrays in this node.
  487. //
  488. void CmBTreeNode::clear(int order)
  489. {
  490.   for (int ii = 0; ii <= order; ii++)
  491.   {
  492.     if (ii < order) _data[ii] = NULL;
  493.     _children[ii] = NULL;
  494.   }
  495. }
  496.  
  497.  
  498. // "split" is called to split this tree node.
  499. //
  500. CmBTreeNode* CmBTreeNode::split(unsigned ordr)
  501. {
  502.   CmBTreeNode *newRight = new CmBTreeNode(_parent, ordr);
  503.   if (!newRight) return NULL;
  504.  
  505.   int ix = 0, midIdx = _total / 2;
  506.   for (int ii = midIdx+1; ii <= _total; ii++, ix++)
  507.   {
  508.     if (ii != _total)
  509.     {
  510.       newRight->_data[ix] = _data[ii];
  511.       newRight->_total++;
  512.       _data[ii] = NULL;
  513.     }
  514.     newRight->_children[ix] = _children[ii];
  515.     _children[ii] = NULL;
  516.     if (newRight->_children[ix]) newRight->_children[ix]->_parent = newRight;
  517.   }
  518.   _total = midIdx;
  519.   return newRight;
  520. }
  521.  
  522.  
  523. // "CmBTreeIterator" is the constructor for the iterator class.
  524. //
  525. CmBTreeIterator::CmBTreeIterator(const CmBTree &Tr) : _tree(Tr)
  526. {
  527.   _node  = _tree._root;
  528.   _index = 0;
  529.   if (_node)                                 // Descend all the way down left.
  530.     while (_node->_children[0])
  531.       _node = _node->_children[0];
  532. }
  533.  
  534.  
  535. // "next" returns the current object and advances the iterator to the
  536. // next object.
  537. //
  538. CmObject* CmBTreeIterator::next()
  539. {
  540.   CmObject* retValue = current();             // Save current object.
  541.   if (!retValue) return NULL;
  542.  
  543.   if (_node->_children[_index+1])             // Traverse all the way down
  544.   {                                           // the left part of the next
  545.     _node = _node->_children[_index+1];       // child branch.
  546.     while (_node->_children[0])
  547.       _node = _node->_children[0];
  548.     _index = 0;
  549.     return retValue;
  550.   }
  551.  
  552.   if (_index < _node->_total-1)               // No child branches, but there
  553.   {                                           // are still objects in this
  554.     _index++;                                 // node so bump the index and
  555.     return retValue;                          // exit.
  556.   }
  557.  
  558.   Bool done = FALSE;                          // Need to back up the tree.
  559.   while (!done)
  560.   {
  561.     if (!_node->_parent)                      // If node has no parent, we
  562.     {                                         // are done iterating.
  563.       _node = NULL;
  564.       done  = TRUE;
  565.     }
  566.  
  567.     else                                      // Node has parent.
  568.     {
  569.       int idx = _node->_parent->index(_node); // What branch were we just in?
  570.       if (idx == -1)                          // Error! - shouldn't happen.
  571.       {
  572.         _node = NULL;
  573.         done  = TRUE;
  574.       }
  575.       else                                    // Got the branch.
  576.       {
  577.         _node = _node->_parent;               // Move up to parent.
  578.         if (idx < _node->_total)              // If not end of data list,
  579.         {                                     // bump index and exit.
  580.           _index = idx;
  581.           done = TRUE;
  582.         }
  583.       }
  584.     }
  585.   }
  586.   return retValue;                            // Return the object.
  587. }
  588.  
  589.  
  590. // "previous" backs the iterator up one object and returns that object.
  591. //
  592. CmObject* CmBTreeIterator::previous()
  593. {
  594.   CmObject* retValue = current();             // Save current object.
  595.   if (!retValue) return NULL;
  596.  
  597.   if (_node->_children[_index])               // Traverse all the way down
  598.   {                                           // the right part of the
  599.     _node = _node->_children[_index];         // previous child branch.
  600.     while (_node->_total && _node->_children[_node->_total-1])
  601.       _node = _node->_children[_node->_total];
  602.     _index = _node->_total-1;
  603.     return retValue;
  604.   }
  605.  
  606.   if (_index > 0)                             // No child branches, but there
  607.   {                                           // are still objects in this
  608.     _index--;                                 // node so decrement the index
  609.     return retValue;                          // and exit.
  610.   }
  611.  
  612.   Bool done = FALSE;                          // Need to back up the tree.
  613.   while (!done)
  614.   {
  615.     if (!_node->_parent)                      // If node has no parent, we
  616.     {                                         // are done iterating.
  617.       _node = NULL;
  618.       done  = TRUE;
  619.     }
  620.  
  621.     else                                      // Node has parent.
  622.     {
  623.       int idx = _node->_parent->index(_node); // What brach were we just in?
  624.       if (idx == -1)                          // Error! - shouldn't happen.
  625.       {
  626.         _node = NULL;
  627.         done  = TRUE;
  628.       }
  629.       else                                    // Got the branch.
  630.       {
  631.         _node = _node->_parent;               // Move up to parent.
  632.         if (idx > 0)                          // If not at beginning,
  633.         {                                     // decrement index and exit.
  634.           _index = idx - 1;
  635.           done   = TRUE;
  636.         }
  637.       }
  638.     }
  639.   }
  640.   return retValue;                            // Return the object.
  641. }
  642.  
  643.  
  644. // "first" moves the iterator to the first object in the tree.
  645. //
  646. void CmBTreeIterator::first()
  647. {
  648.   _node  = _tree._root;
  649.   _index = 0;
  650.  
  651.   if (_node)
  652.     while (_node->_children[0])
  653.       _node = _node->_children[0];
  654. }
  655.  
  656.  
  657. // "last" moves the iterator to the last object in the tree.
  658. //
  659. void CmBTreeIterator::last()
  660. {
  661.   _node = _tree._root;
  662.   if (_node)
  663.   {
  664.     while (_node->_children[_node->_total])
  665.       _node = _node->_children[_node->_total];
  666.     _index = _node->_total - 1;
  667.   }
  668. }
  669.